
package com.hlkj.pay.controller.merchant;
/*
 * Hlpay-Plus aggregate payment system.
 * Copyright (c) 2024-2025 Hlpay Team Copyright has the right of final interpretation.
 */

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import com.hlkj.framework.common.pojo.CommonResult;
import com.hlkj.framework.common.pojo.LocalContext;
import com.hlkj.framework.common.pojo.LocalRequest;
import com.hlkj.framework.common.pojo.PageResult;
import com.hlkj.framework.common.util.collection.CollectionUtils;
import com.hlkj.framework.common.util.json.JsonUtils;
import com.hlkj.pay.app.common.IDownloadExcelService;
import com.hlkj.pay.app.merchant.IMerchantInfoAppService;
import com.hlkj.pay.app.transfer.PayChannelDoToResp;
import com.hlkj.pay.app.transfer.ProviderDoToResp;
import com.hlkj.pay.common.CommonResultCode;
import com.hlkj.pay.common.MerchantResultCode;
import com.hlkj.pay.controller.BaseController;
import com.hlkj.pay.dto.LocalAdminUserRequest;
import com.hlkj.pay.dto.merchant.MerchantInfoDto;
import com.hlkj.pay.dto.merchant.MerchantInfoQueryDto;
import com.hlkj.pay.dto.merchant.ProviderChannelFeeConfigList;
import com.hlkj.pay.dto.pay.PayChannelQueryDto;
import com.hlkj.pay.dto.pay.PayWayQueryDto;
import com.hlkj.pay.dto.pay.ProviderQueryDto;
import com.hlkj.pay.enums.CommonEnum;
import com.hlkj.pay.enums.MerchantEnum;
import com.hlkj.pay.infrastructure.model.admin.AdminUserDO;
import com.hlkj.pay.infrastructure.model.finance.MerchantAmountDO;
import com.hlkj.pay.infrastructure.model.merchant.MerchantConfigDO;
import com.hlkj.pay.infrastructure.model.merchant.MerchantInfoDO;
import com.hlkj.pay.infrastructure.model.pay.PayChannelDO;
import com.hlkj.pay.infrastructure.model.pay.PayWayDO;
import com.hlkj.pay.infrastructure.model.pay.ProviderChannelConfigDO;
import com.hlkj.pay.infrastructure.model.pay.ProviderInfoDO;
import com.hlkj.pay.service.admin.IAdminUserService;
import com.hlkj.pay.service.merchant.IAgentService;
import com.hlkj.pay.service.merchant.IMerchantConfigService;
import com.hlkj.pay.service.merchant.IMerchantService;
import com.hlkj.pay.service.pay.IPayChannelService;
import com.hlkj.pay.service.pay.IPayWayService;
import com.hlkj.pay.service.pay.IProviderService;
import com.hlkj.pay.util.DateUtils;
import com.hlkj.pay.vo.merchant.req.info.*;
import com.hlkj.pay.vo.merchant.resp.info.MerchantFeeConfigResp;
import com.hlkj.pay.vo.merchant.resp.info.MerchantInfoDetailResp;
import com.hlkj.pay.vo.merchant.resp.info.MerchantInfoPageResp;
import com.hlkj.pay.vo.order.resp.export.MerchantInfoFileExport;
import com.hlkj.pay.vo.pay.resp.PayChannelListResp;
import com.hlkj.pay.vo.pay.resp.PayWayResp;
import com.hlkj.pay.vo.pay.resp.ProviderInfoResp;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.date.DatePattern;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;

/**
 * @author HlpayTeam
 * @date 2024/09/12 11:32
 */
@Tag(name = "商户信息管理")
@RestController
@RequestMapping("/v1/merchant/info")
@RequiredArgsConstructor
public class MerchantInfoController extends BaseController {

    private final IMerchantInfoAppService merchantInfoAppService;

    private final IMerchantService merchantService;

    private final IAdminUserService userService;

    private final IMerchantConfigService merchantConfigService;

    private final IProviderService providerService;

    private final IPayChannelService payChannelService;

    private final IPayWayService payWayService;

    private final IDownloadExcelService downloadExcelService;

    private final IAgentService agentService;

    @Operation(summary = "商户注册")
    @PostMapping("/register")
    CommonResult<String> register(@Validated @RequestBody MerchantRegisterReq merchantRegisterReq) {
        return merchantInfoAppService.register(merchantRegisterReq);
    }

    @Operation(summary = "商户列表分页")
    @GetMapping("")
    CommonResult<PageResult<MerchantInfoPageResp>> queryPage(@Validated MerchantInfoPageReq merchantAccessPageReq) {
        MerchantInfoQueryDto merchantInfoQueryDto = new MerchantInfoQueryDto();
        merchantInfoQueryDto.setLikeName(merchantAccessPageReq.getName());
        merchantInfoQueryDto.setLikeShortName(merchantAccessPageReq.getShortName());
        merchantInfoQueryDto.setLikeAccount(merchantAccessPageReq.getAccount());
        merchantInfoQueryDto.setLikeLegalPhone(merchantAccessPageReq.getLegalPhone());
        merchantInfoQueryDto.setLikeSuperAgent(merchantAccessPageReq.getSuperAgent());
        merchantInfoQueryDto.setStatus(merchantAccessPageReq.getStatus());
        merchantInfoQueryDto.setSignStatus(merchantAccessPageReq.getSignStatus());
        merchantInfoQueryDto.setPageNo(merchantAccessPageReq.getPageNo());
        merchantInfoQueryDto.setPageSize(merchantAccessPageReq.getPageSize());
        merchantInfoQueryDto.setSnType(MerchantEnum.MERCHANT_SN_TYPE.MERCHANT.getCode());
        merchantInfoQueryDto.setType(merchantAccessPageReq.getType());
        merchantInfoQueryDto.setSn(merchantAccessPageReq.getSn());
        merchantInfoQueryDto.setMerType(merchantAccessPageReq.getMerType());
        processQueryDate(merchantAccessPageReq, merchantInfoQueryDto);
        PageResult<MerchantInfoDto> page = merchantService.queryPage(merchantInfoQueryDto);
        List<MerchantInfoDto> list = page.getList();
        if (CollectionUtils.isEmpty(list)) {
            return buildPageResult(page, Collections.emptyList());
        }
        if (merchantAccessPageReq.getExport() == 1) {
            String fileName = merchantAccessPageReq.getExportName();
            if (!StringUtils.hasText(fileName)) fileName = "商户列表导出_" + DateUtils.getDateString(DatePattern.PURE_DATETIME_PATTERN);
            downloadExcelService.createExcel(fileName, merchantInfoQueryDto, MerchantInfoFileExport.class);
            return CommonResult.success();
        }

        CopyOptions copyOptions = CopyOptions.create().setIgnoreError(true).setIgnoreProperties("sence");
        List<MerchantInfoPageResp> merchantInfoPageResps = BeanUtil.copyToList(list, MerchantInfoPageResp.class, copyOptions);
        List<String> superAgentList = merchantInfoPageResps.stream().map(merchantInfoPageResp -> merchantInfoPageResp.getSuperAgent()).collect(Collectors.toList());
        List<String> snList = merchantInfoPageResps.stream().map(merchantInfoPageResp -> merchantInfoPageResp.getSn()).collect(Collectors.toList());
        Map<String, MerchantInfoDO> merchantInfoDOMap = new HashMap<>();
        Map<String, ProviderInfoDO> providerInfoMap = new HashMap<>();
        Map<String, List<String>> providerCodeMap = new HashMap<>();
        if (!CollectionUtils.isEmpty(superAgentList)) {
            merchantInfoQueryDto = new MerchantInfoQueryDto();
            merchantInfoQueryDto.setSnList(superAgentList);
            List<MerchantInfoDO> merchantInfoList = merchantService.queryList(merchantInfoQueryDto);
            merchantInfoDOMap = merchantInfoList.stream().collect(Collectors.toMap(MerchantInfoDO::getSn, Function.identity(), (t1, t2) -> t1));
        }

        List<Long> operterList = merchantInfoPageResps.stream().map(merchantInfoPageResp -> merchantInfoPageResp.getOperateId()).collect(Collectors.toList());
        Map<Long, AdminUserDO> userDOMap = new HashMap<>();
        if (!CollectionUtils.isEmpty(operterList)) {
            List<AdminUserDO> userList = userService.queryUserList(operterList);
            userDOMap = userList.stream().collect(Collectors.toMap(AdminUserDO::getId, Function.identity(), (t1, t2) -> t1));
        }

        List<MerchantConfigDO> merchantConfigList = merchantConfigService.queryConfig(snList);
        if (!CollectionUtils.isEmpty(merchantConfigList)) {
            List<String> providerCodeList = new ArrayList<>();
            merchantConfigList.stream().forEach(merchantConfigDO -> {
                providerCodeList.addAll(merchantConfigDO.getProviderCodeList());
                providerCodeMap.put(merchantConfigDO.getSn(), merchantConfigDO.getProviderCodeList());

            });
            List<ProviderInfoDO> providerInfoList = providerService.queryByCodes(providerCodeList);
            providerInfoMap = providerInfoList.stream().collect(Collectors.toMap(ProviderInfoDO::getCode, Function.identity(), (t1, t2) -> t1));
        }
        Map<String, ProviderInfoDO> finalProviderInfoMap = providerInfoMap;
        for (MerchantInfoPageResp merchantInfoPageResp : merchantInfoPageResps) {
            MerchantInfoDO merchantInfoDO = merchantInfoDOMap.get(merchantInfoPageResp.getSuperAgent());
            if (merchantInfoDO != null) {
                merchantInfoPageResp.setSuperAgentName(merchantInfoDO.getName());
            }
            AdminUserDO adminUserDO = userDOMap.get(merchantInfoPageResp.getOperateId());
            if (adminUserDO != null) {
                merchantInfoPageResp.setOperateName(adminUserDO.getName());
            }
            List<String> providerCodeList = providerCodeMap.get(merchantInfoPageResp.getSn());
            if (!CollectionUtils.isEmpty(providerCodeList)) {
                providerCodeList.stream().forEach(providerCode -> {
                    merchantInfoPageResp.getProviderInfoList().add(ProviderDoToResp.INSTANCE.providerInfoResp(finalProviderInfoMap.get(providerCode)));
                });
            }
        }
        return buildPageResult(page, merchantInfoPageResps);
    }

    @Operation(summary = "商户列表不分页")
    @GetMapping("/list")
    CommonResult<List<MerchantInfoDetailResp>> queryList(@Validated MerchantInfoPageReq merchantInfoPageReq) {
        MerchantInfoQueryDto merchantInfoQueryDto = new MerchantInfoQueryDto();
        merchantInfoQueryDto.setLikeName(merchantInfoPageReq.getName());
        merchantInfoQueryDto.setLikeShortName(merchantInfoPageReq.getShortName());
        merchantInfoQueryDto.setLikeAccount(merchantInfoPageReq.getAccount());
        merchantInfoQueryDto.setLikeLegalPhone(merchantInfoPageReq.getLegalPhone());
        merchantInfoQueryDto.setLikeSuperAgent(merchantInfoPageReq.getSuperAgent());
        merchantInfoQueryDto.setStatus(merchantInfoPageReq.getStatus());
        merchantInfoQueryDto.setSignStatus(merchantInfoPageReq.getSignStatus());
        merchantInfoQueryDto.setSnType(MerchantEnum.MERCHANT_SN_TYPE.MERCHANT.getCode());
        merchantInfoQueryDto.setSn(merchantInfoPageReq.getSn());
        List<MerchantInfoDO> list = merchantService.queryList(merchantInfoQueryDto);
        if (CollectionUtils.isEmpty(list)) {
            return CommonResult.success(Collections.emptyList());
        }
        CopyOptions copyOptions = CopyOptions.create().setIgnoreError(true).setIgnoreProperties("sence");
        return CommonResult.success(BeanUtil.copyToList(list, MerchantInfoDetailResp.class, copyOptions));
    }

    @Operation(summary = "商户详情")
    @GetMapping("/detail")
    CommonResult<MerchantInfoDetailResp> detail(@RequestParam(value = "sn", required = false) String sn) {
        // 商户平台没有传sn
        if (!StringUtils.hasText(sn)) {
            LocalAdminUserRequest localAdminUserRequest = (LocalAdminUserRequest) LocalContext.get();
            sn = localAdminUserRequest.getSn();
            if (!StringUtils.hasText(sn)) {
                return CommonResult.error(MerchantResultCode.MERCHANT_NOT_EFFECT);
            }
        }
        MerchantInfoDO merchantInfoDO = merchantService.queryMerchant(sn);
        if (merchantInfoDO == null) {
            return CommonResult.success();
        }
        MerchantAmountDO merchantAmountDO = merchantService.queryMerchantAmount(sn);

        MerchantInfoDetailResp merchantInfoDetailResp = BeanUtil.copyProperties(merchantInfoDO, MerchantInfoDetailResp.class, "scene");
        // 金额信息复制
        BeanUtil.copyProperties(merchantAmountDO, merchantInfoDetailResp);
        MerchantConfigDO merchantConfigDO = merchantInfoAppService.queryConfig(sn);
        if (merchantConfigDO != null) {
            merchantInfoDetailResp.setProviderCodeList(merchantConfigDO.getProviderCodeList());
            merchantInfoDetailResp.setChannelCodeList(merchantConfigDO.getChannelCodeList());
            if (!CollectionUtils.isEmpty(merchantConfigDO.getProviderCodeList())) {
                List<ProviderInfoDO> providerInfoList = providerService.queryByCodes(merchantConfigDO.getProviderCodeList());
                merchantInfoDetailResp.setProviderList(ProviderDoToResp.INSTANCE.providerInfoRespList(providerInfoList));
            }
            if (!CollectionUtils.isEmpty(merchantConfigDO.getChannelCodeList())) {
                List<PayChannelDO> payChannelList = payChannelService.queryByCodes(merchantConfigDO.getChannelCodeList());
                merchantInfoDetailResp.setChannelList(PayChannelDoToResp.INSTANCE.payChannelListRespList(payChannelList));
            }
        }
        // if (StringUtils.hasText(merchantInfoDO.getScene())) {
        //     merchantInfoDetailResp.setScene(JsonUtils.parseObject(merchantInfoDO.getScene(), Scene.class));
        // }

        // 代理商查询
        if(MerchantEnum.MERCHANT_SN_TYPE.MERCHANT.getCode() == merchantInfoDO.getSnType()){
            MerchantInfoDO agentInfoDO = merchantService.queryMerchantNoCache(merchantInfoDO.getSuperAgent());
            if(agentInfoDO != null){
                merchantInfoDetailResp.setAgentCommRateBase(agentInfoDO.getCommRateBase());
            }
        }


        return CommonResult.success(merchantInfoDetailResp);
    }

    @Operation(summary = "获取商户开通的支付方式")
    @GetMapping("/detail/payway")
    CommonResult<List<PayWayResp>> payway(@RequestParam(value = "sn", required = false) String sn, @RequestParam(value = "channelCode", required = false) String channelCode) {
        // 商户平台没有传sn
        if (!StringUtils.hasText(sn)) {
            LocalAdminUserRequest localAdminUserRequest = (LocalAdminUserRequest) LocalContext.get();
            sn = localAdminUserRequest.getSn();
            if (!StringUtils.hasText(sn)) {
                return CommonResult.error(MerchantResultCode.MERCHANT_NOT_EFFECT);
            }
        }
        MerchantConfigDO merchantConfigDO = merchantInfoAppService.queryConfig(sn);
        if (merchantConfigDO != null) {
            if (StringUtils.hasText(merchantConfigDO.getFeeConfig())) {
                List<MerchantFeeConfigResp> providerChannelFeeConfigList = JsonUtils.parseArray(merchantConfigDO.getFeeConfig(), MerchantFeeConfigResp.class);
                List<String> payWayCodes = providerChannelFeeConfigList.stream()
                        .filter(merchantFeeConfigResp -> CommonEnum.YES_NO_TYPE.YES.getCode().equals(merchantFeeConfigResp.getStatus()))
                        .map(merchantFeeConfigResp -> merchantFeeConfigResp.getPayWayCode()).collect(Collectors.toList());
                if (StringUtils.hasText(channelCode)) {
                    PayChannelDO payChannelDO = payChannelService.queryByCode(channelCode);
                    if (!CollectionUtils.isEmpty(payChannelDO.getPayWapCodeList())) {
                        Collection<String> intersection = CollectionUtils.intersection(payWayCodes, payChannelDO.getPayWapCodeList());
                        if (CollectionUtils.isEmpty(intersection)) {
                            return CommonResult.success(Collections.emptyList());
                        }
                        payWayCodes = new ArrayList<>(intersection);
                    }
                }

                PayWayQueryDto payWayQueryDto = new PayWayQueryDto();
                payWayQueryDto.setCodes(payWayCodes);
                List<PayWayDO> payWayList = payWayService.queryList(payWayQueryDto);
                return CommonResult.success(BeanUtil.copyToList(payWayList, PayWayResp.class));
            }
            else {
                return CommonResult.success(Collections.emptyList());
            }
        }
        else {
            return CommonResult.success(Collections.emptyList());
        }
    }

    @Operation(summary = "删除商户")
    @DeleteMapping("")
    CommonResult<Void> delMerchant(@Validated @RequestBody UpdateMerchantStatusReq updateMerchantStatusReq) {
        return merchantInfoAppService.delMerchant(updateMerchantStatusReq.getSn());
    }

    @Operation(summary = "更新商户信息")
    @PutMapping("")
    CommonResult<Void> updateMerchantInfo(@Validated @RequestBody MerchantInfoUpdateReq merchantInfoUpdateReq) {
        return merchantInfoAppService.updateMerchantInfo(merchantInfoUpdateReq);
    }

    @Operation(summary = "更新商户状态")
    @PostMapping("/status")
    CommonResult<Void> updateStatus(@Validated @RequestBody UpdateMerchantStatusReq updateStatusReq) {
        return merchantInfoAppService.updateStatus(updateStatusReq);
    }

    @Operation(summary = "更新商户交易状态")
    @PostMapping("/status/tran")
    CommonResult<Void> updateTranStatus(@Validated @RequestBody UpdateMerchantStatusReq updateStatusReq) {
        return merchantInfoAppService.updateTranStatus(updateStatusReq);
    }

    @Operation(summary = "获取商户费率配置")
    @GetMapping("/feeConfig")
    CommonResult<List<MerchantFeeConfigResp>> queryProviderFeeConfig(@RequestParam(name = "sn") String sn) {
        return merchantInfoAppService.queryFeeConfig(sn);
    }

    @Operation(summary = "获取商户对应的服务商")
    @GetMapping("/provider")
    CommonResult<List<ProviderInfoResp>> queryProviderList(@RequestParam(name = "sn", required = false) String sn) {
        ProviderQueryDto payWayQueryDO = new ProviderQueryDto();
        if (!StringUtils.hasText(sn)) {
            sn = LocalContext.get().getQuerySn();
        }
        if (StringUtils.hasText(sn)) {
            MerchantConfigDO merchantConfigDO = merchantInfoAppService.queryConfig(sn);
            if (merchantConfigDO == null) {
                return CommonResult.success(Collections.emptyList());
            }
            if (CollectionUtils.isEmpty(merchantConfigDO.getProviderCodeList())) {
                return CommonResult.success(Collections.emptyList());
            }
            if (!CollectionUtils.isEmpty(merchantConfigDO.getProviderCodeList())) {
                // return CommonResult.success(Collections.emptyList());
                payWayQueryDO.setCodes(merchantConfigDO.getProviderCodeList());
            }
        }
        List<ProviderInfoDO> payWayList = providerService.queryList(payWayQueryDO);
        if (CollectionUtils.isEmpty(payWayList)) {
            return CommonResult.success(Collections.emptyList());
        }
        return CommonResult.success(ProviderDoToResp.INSTANCE.providerInfoRespList(payWayList));
    }

    @Operation(summary = "获取商户对应的服务商下的通道")
    @GetMapping("/provider/channel")
    CommonResult<List<PayChannelListResp>> queryProviderChannelList(PayChannelQueryReq payChannelQueryReq) {
        Set<String> channelCodeList = null;
        PayChannelQueryDto payChannelQueryDto=new PayChannelQueryDto();
        LocalRequest localRequest = LocalContext.get();
        if (!StringUtils.hasText(payChannelQueryDto.getSn())) {
            payChannelQueryDto.setSn(localRequest.getQuerySn());
        }
        if (StringUtils.hasText(payChannelQueryDto.getSn())) {
            MerchantConfigDO merchantConfigDO = merchantInfoAppService.queryConfig(payChannelQueryDto.getSn());
            if (merchantConfigDO == null) {
                return CommonResult.success(Collections.emptyList());
            }
            if (CollectionUtils.isEmpty(merchantConfigDO.getProviderCodeList())) {
                return CommonResult.success(Collections.emptyList());
            }
            if (CollectionUtils.isEmpty(merchantConfigDO.getChannelCodeList())) {
                return CommonResult.success(Collections.emptyList());
            }
            if (!merchantConfigDO.getProviderCodeList().contains(payChannelQueryReq.getProviderCode())) {
                return CommonResult.success(Collections.emptyList());
            }
            channelCodeList = new HashSet<>(merchantConfigDO.getChannelCodeList());
        }
        List<ProviderChannelConfigDO> providerChannelConfigList = providerService.queryConfigList(payChannelQueryReq.getProviderCode());
        Set<String> codes = providerChannelConfigList.stream().filter(providerChannelConfigDO -> CommonEnum.YES_NO_TYPE.YES.getCode().equals(providerChannelConfigDO.getStatus()))
                .map(providerChannelConfigDO -> providerChannelConfigDO.getChannelCode()).collect(Collectors.toSet());
        if (channelCodeList != null) {
            // 获取两个集合的交集
            codes.retainAll(channelCodeList);
        }
        payChannelQueryDto.setCodes(new ArrayList<>(codes));
        payChannelQueryDto.setApplyType(payChannelQueryReq.getApplyType());
        payChannelQueryDto.setMerchantType(payChannelQueryReq.getMerchantType());
        payChannelQueryDto.setSpecialMerchantType(payChannelQueryReq.getSpecialMerchantType());
        payChannelQueryDto.setType(payChannelQueryReq.getType());
        List<PayChannelDO> payWayList = payChannelService.queryList(payChannelQueryDto);
        if (CollectionUtils.isEmpty(payWayList)) {
            return CommonResult.success(Collections.emptyList());
        }
        return CommonResult.success(PayChannelDoToResp.INSTANCE.payChannelListRespList(payWayList));
    }

    @Operation(summary = "保存商户费率配置")
    @PostMapping("/feeConfig")
    CommonResult<Void> saveProviderFeeConfig(@RequestBody MerchantFeeConfigReq merchantFeeConfigReq) {
        List<ProviderChannelFeeConfigList> channelFeeConfigLists = merchantFeeConfigReq.getProviderChannelFeeConfigList().stream()
                .filter(providerChannelFeeConfigList -> CommonEnum.YES_NO_TYPE.YES.getCode().equals(providerChannelFeeConfigList.getStatus())).collect(Collectors.toList());
        merchantFeeConfigReq.setProviderChannelFeeConfigList(channelFeeConfigLists);
        try {
            return merchantInfoAppService.saveFeeConfig(merchantFeeConfigReq);
        }
        catch (Exception e) {
            return CommonResult.error(CommonResultCode.PARAMETER_MISSING.getCode(), e.getMessage());
        }
    }

}
